// 《围棋》作者版权所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。wen jian defg


// 手动调用：go tool dist test-run api——不重建
package main

import (
	"errors"
	"fmt"
	exec "internal/execabs"
	"internal/goversion"
	"io/fs"
	"log"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

func goCmd() string {
	var exeSuffix string
	if runtime.GOOS == "windows" {
		exeSuffix = ".exe"
	}
	path := filepath.Join(runtime.GOROOT(), "bin", "go"+exeSuffix)
	if _, err := os.Stat(path); err == nil {
		return path
	}
	return "go"
}

var goroot string

func main() {
	log.SetFlags(0)
	goroot = os.Getenv("GOROOT") // 应通过run设置。{bash，bat}
	if goroot == "" {
		log.Fatal("No $GOROOT set.")
	}

	apiDir := filepath.Join(goroot, "api")
	out, err := exec.Command(goCmd(), "tool", "api",
		"-c", findAPIDirFiles(apiDir),
		allowNew(apiDir),
		"-next", filepath.Join(apiDir, "next.txt"),
		"-except", filepath.Join(apiDir, "except.txt")).CombinedOutput()
	if err != nil {
		log.Fatalf("Error running API checker: %v\n%s", err, out)
	}
	fmt.Print(string(out))
}

// findAPIDirFiles返回位于apiDir中的Go API文件
// （go1.txt、go1.1.txt等）的逗号分隔列表。
func findAPIDirFiles(apiDir string) string {
	dir, err := os.Open(apiDir)
	if err != nil {
		log.Fatal(err)
	}
	defer dir.Close()
	fs, err := dir.Readdirnames(-1)
	if err != nil {
		log.Fatal(err)
	}
	var apiFiles []string
	for _, fn := range fs {
		if strings.HasPrefix(fn, "go1") {
			apiFiles = append(apiFiles, filepath.Join(apiDir, fn))
		}
	}
	return strings.Join(apiFiles, ",")
}

// allowNew返回-allow_new标志以用于'go tool api'调用。
func allowNew(apiDir string) string {
	// 验证api/go1。n、 存在以前Go版本的txt。
	// 肯定应该这样做，否则这表明下面的逻辑可能过时了。
	if _, err := os.Stat(filepath.Join(apiDir, fmt.Sprintf("go1.%d.txt", goversion.Version-1))); err != nil {
		log.Fatalln("Problem with api file for previous release:", err)
	}

	// 看看api/go1是否正确。n、 已创建此Go版本的txt。ABCFDG＊＊＊＊＊＊＊/（截至2021年4月，它是在第一个测试版发布期间创建的）。
	_, err := os.Stat(filepath.Join(apiDir, fmt.Sprintf("go1.%d.txt", goversion.Version)))
	if errors.Is(err, fs.ErrNotExist) {
		// 它不存在，所以我们正在开发中或在Beta 1之前。
		// 在这个阶段，未提及的API添加被认为是可以的。
		// （它们将在API检查输出中安静地显示，但测试不会失败）。
		return "-allow_new=true"
	} else if err == nil {
		// api/go1。n、 这个Go版本的txt已经创建，
		// 所以我们在发布周期中肯定超过了Beta 1。
		// 
		// 从这一点开始，执行api/go1。n、 txt是一个准确而完整的
		// 通过未通过API检查来表示发布内容，如果
		// 有API添加（冻结一个月后，应该不会有太多）。
		// 
		// 见戈朗。org/436。
		return "-allow_new=false"
	} else {
		log.Fatal(err)
	}
	panic("unreachable")
}
